﻿using System;
using System.Collections.Generic;

using TradeClient.Logic.Entity;
using WAF.EntityFramework;

namespace TradeClient.Logic.TradeCore
{
    /// <summary>
    /// 持仓类
    /// </summary>
    public class Position
    {
        /// <summary>
        /// 策略名
        /// </summary>
        public string Policy { get; set; }

        /// <summary>
        /// 市场
        /// </summary>
        public MarketType Market { get; set; }

        /// <summary>
        /// 账号
        /// </summary>
        public string Account { get; set; }

        /// <summary>
        /// 代码
        /// </summary>
        public string Code { get; set; }

        /// <summary>
        /// 买卖方向
        /// </summary>
        public DirectionType Direction { get; set; }

        /// <summary>
        /// K线级别
        /// </summary>
        public int Level { get; set; }

        /// <summary>
        /// K线单位
        /// </summary>
        public KLineUnitType LevelUnit { get; set; }

        /// <summary>
        /// 数量
        /// </summary>
        public int Volume { get; set; }

        /// <summary>
        /// 价格
        /// </summary>
        public double Price { get; set; }


        /// <summary>
        /// 唯一键
        /// </summary>
        private string key;

        /// <summary>
        /// 数据库持仓类
        /// </summary>
        private Logic.Entity.Position position;

        /// <summary>
        /// 详细持仓
        /// </summary>
        private List<PositionDetail> positionDetails;


        /// <summary>
        /// 开仓
        /// </summary>
        /// <param name="tradeTime">交易时间</param>
        /// <param name="price">开仓价格</param>
        /// <param name="volume">开仓数量</param>
        public void Open(DateTime tradeTime, double price, int volume)
        {
            //结果采取四舍六入法，保留两位小数
            this.Price = Math.Round((this.Price * this.Volume + price * volume) / (this.Volume + volume), 2);

            this.Volume += volume;

            PositionDetail detail = new PositionDetail();
            detail.Price = price;
            detail.Volume = volume;
            detail.OpenDateTime = tradeTime;

            UpdateToDb();
        }

        /// <summary>
        /// 平仓
        /// </summary>
        /// <param name="tradeTime">交易时间</param>
        /// <param name="price">平仓价格</param>
        /// <param name="volume">平仓数量</param>
        public void Close(DateTime tradeTime, double price, int volume)
        {
            //结果采取四舍六入法，保留两位小数
            this.Price = Math.Round((this.Price * this.Volume - price * volume) / (this.Volume - volume), 2);

            this.Volume -= volume;

            DateTime lastTime = DateTime.MinValue;

            foreach (PositionDetail detail in positionDetails)
            {
                DateTime positionTime = DateTime.Parse(detail.OpenDateTime);

                if (lastTime.CompareTo(positionTime) < 0)
                    lastTime = positionTime;
            }

            UpdateToDb();

            //如果已经全部平仓则清除持仓记录
            if (this.Volume == 0)
            {
                PositionManager.GetInstance().Remove(this);
                EntityAction.Delete(this.positionRecord);
            }
        }

        /// <summary>
        /// 取得唯一键
        /// </summary>
        /// <returns>唯一键</returns>
        public string GetKey()
        {
            if (key == null)
            {
                System.Text.StringBuilder sb = new System.Text.StringBuilder();

                sb.Append(Market.ToString()).Append("_")
                  .Append(Policy).Append("_")
                  .Append(Account).Append("_")
                  .Append(Code).Append("_")
                  .Append(Direction.ToString()).Append("_")
                  .Append(Level.ToString()).Append("_")
                  .Append(Unit.ToString());

                key = sb.ToString();
            }

            return key;
        }



















        /// <summary>
        /// 持仓记录
        /// </summary>
        private PositionRecord positionRecord;

        /// <summary>
        /// 唯一ID
        /// </summary>
        public string Id { get; private set; }

        /// <summary>
        /// 交易时产生的新的持仓记录
        /// </summary>
        /// <param name="tradeField">交易字段</param>
        public Position(TradeField tradeField)
        {
            this.positionRecord             = new PositionRecord();
            this.positionRecord.Policy      = tradeField.Policy;
            this.positionRecord.Market      = tradeField.Market.ToString();
            this.positionRecord.Account     = tradeField.Account;
            this.positionRecord.Code        = tradeField.Code;
            this.positionRecord.Direction   = tradeField.Direction.ToString();
            this.positionRecord.Level       = tradeField.Level;
            this.positionRecord.Unit        = tradeField.Unit.ToString();

            //避免重复开仓
            tradeField.Price  = 0;
            tradeField.Volume = 0;

            InitField(tradeField);

            //将持仓记录到数据库中
            this.positionRecord.Id = EntityAction.Insert(this.positionRecord);
        }

        /// <summary>
        /// 从数据库中读取的持仓记录
        /// </summary>
        /// <param name="record">持仓记录</param>
        public Position(PositionRecord record)
        {
            this.positionRecord = record;

            TradeField tradeField   = new TradeField();
            tradeField.Policy       = this.positionRecord.Policy;
            tradeField.Market       = (MarketType)Enum.Parse(typeof(MarketType), this.positionRecord.Market);
            tradeField.Account      = this.positionRecord.Account;
            tradeField.Code         = this.positionRecord.Code;
            tradeField.Direction    = (DirectionType)Enum.Parse(typeof(DirectionType), this.positionRecord.Direction);
            tradeField.Level        = this.positionRecord.Level;
            tradeField.Unit         = (KLineUnitType)Enum.Parse(typeof(KLineUnitType), this.positionRecord.Unit);
            tradeField.Price        = this.positionRecord.Price;
            tradeField.Volume       = this.positionRecord.Volume;

            InitField(tradeField);
        }


        /******************************** private ********************************/

        /// <summary>
        /// 初始化字段
        /// </summary>
        /// <param name="tradeField">交易字段</param>
        private void InitField(TradeField tradeField)
        {
            this.Id         = tradeField.GetId();
            this.Policy     = tradeField.Policy;
            this.Market     = tradeField.Market;
            this.Account    = tradeField.Account;
            this.Code       = tradeField.Code;
            this.Direction  = tradeField.Direction;
            this.Level      = tradeField.Level;
            this.Unit       = tradeField.Unit;
            this.Price      = tradeField.Price;
            this.Volume     = tradeField.Volume;
        }

        /// <summary>
        /// 更新数据库中的持仓记录
        /// </summary>
        private void UpdateToDb()
        {
            this.positionRecord.Volume = this.Volume;
            this.positionRecord.Price  = this.Price;

            EntityAction.Update(this.positionRecord);
        }
    }
}
